//
//  KataOneTests.m
//  CodeKatas
//
//  Created by Viktor Lazarevich on 27-Feb-10.
//  Copyright 2010 Home. All rights reserved.
//

#import "PrimitivesTests.h"
#import "Primitives.h"

@implementation PrimitivesTests

// --- SetUp and TearDown methods --- //
- (void)setUp {
}
- (void)tearDown {
}


// --- Primitives tests --- //
- (void)testPrimitiveMoneyCreateSimple {
	Money m = MakeMoney(1, 92);
	STAssertEquals(m.dollars, 1, @"Expected 1 dollar, but was %i", m.dollars);
	STAssertEquals(m.cents, 92, @"Expected 92 cents, but was %i", m.cents);
	STAssertEquals(TotalCents(m), 192, @"Expected 192 cents total, but was %i", TotalCents(m));
}

- (void)testPrimitiveMoneyCreateComplex {
	Money m = MakeMoney(3, 164);
	STAssertEquals(m.dollars, 4, @"Expected 4 dollars, but was %i", m.dollars);
	STAssertEquals(m.cents, 64, @"Expected 64 cents, but was %i", m.cents);
	STAssertEquals(TotalCents(m), 464, @"Expected 464 cents total, but was %i", TotalCents(m));
}

- (void)testPrimitiveMoneyCreateNegativeSimple {
	Money m = MakeMoney(-2, -34);
	STAssertEquals(m.dollars, -3, @"Expected -3 dollars, but was %i", m.dollars);
	STAssertEquals(m.cents, 66, @"Expected 66 cents, but was %i", m.cents);
	STAssertEquals(TotalCents(m), -234, @"Expected -234 cents total, but was %i", TotalCents(m));
}

- (void)testPrimitiveMoneySum {
	Money m1 = MakeMoney(2, 44);
	Money m2 = MakeMoney(3, 78);
	Money result = SumMoney(m1, m2);
	STAssertEquals(result.dollars, 6, @"Expected 6 dollars, but was %i", result.dollars);
	STAssertEquals(result.cents, 22, @"Expected 22 cents, but was %i", result.cents);
	STAssertEquals(TotalCents(result), 622, @"Expected 622 cents total, but was %i", TotalCents(result));
}

- (void)testPrimitiveMoneySubtractSimple {
	Money m1 = MakeMoney(6, 22);
	Money m2 = MakeMoney(3, 54);
	Money result = SubtractMoney(m1, m2);
	STAssertEquals(result.dollars, 2, @"Expected 2 dollars, but was %i", result.dollars);
	STAssertEquals(result.cents, 68, @"Expected 68 cents, but was %i", result.cents);
	STAssertEquals(TotalCents(result), 268, @"Expected 268 cents total, but was %i", TotalCents(result));
}

- (void)testPrimitiveMoneySubtractNegative {
	Money m1 = MakeMoney(2, 42);
	Money m2 = MakeMoney(4, 81);
	Money result = SubtractMoney(m1, m2);
	STAssertEquals(result.dollars, -3, @"Expected -3 dollars, but was %i", result.dollars);
	STAssertEquals(result.cents, 61, @"Expected 61 cents, but was %i", result.cents);
	STAssertEquals(TotalCents(result), -239, @"Expected -239 cents total, but was %i", TotalCents(result));
}

- (void)testPrimitiveMoneyFormatPositive {
	Money m = MakeMoney(2, 99);
	STAssertTrue([FormatMoney(m) isEqualToString:@"$2.99"], @"Expected $2.99, but was %@", FormatMoney(m));
}

- (void)testPrimitiveMoneyFormatNegative {
	Money m = MakeMoney(-2, -46);
	STAssertTrue([FormatMoney(m) isEqualToString:@"($2.46)"], @"Expected ($2.46), but was %@", FormatMoney(m));
}

- (void)testPrimitiveMoneyFormatThousands {
	Money m = MakeMoney(1999, 0);
	STAssertTrue([FormatMoney(m) isEqualToString:@"$1 999.00"], @"Expected $1 999.00, but was %@", FormatMoney(m));
}

- (void)testPrimitiveQuantityCreateFromPieces {
	Quantity q = MakeQuantityFromPieces(3);
	STAssertEqualsWithAccuracy(q.quantity, 3.0, 0.0001, @"Expected 3.0, but was %f", q.quantity);
	STAssertEquals(q.unit, QuantityUnitPiece, @"Expected Piece, but was %i", q.unit);
}

- (void)testPrimitiveQuantityCreateFromPounds {
	Quantity q = MakeQuantityFromPounds(3.5);
	STAssertEqualsWithAccuracy(q.quantity, 3.5, 0.0001, @"Expected 3.5, but was %f", q.quantity);
	STAssertEquals(q.unit, QuantityUnitPound, @"Expected Pound, but was %i", q.unit);
}

- (void)testPrimitiveQuantitySumPieces {
	Quantity q1 = MakeQuantityFromPieces(2);
	Quantity q2 = MakeQuantityFromPieces(4);
	Quantity result = SumQuantity(q1, q2);
	
	STAssertEqualsWithAccuracy(result.quantity, 6.0, 0.0001, @"Expected 6, but was %f", result.quantity);
	STAssertEquals(result.unit, QuantityUnitPiece, @"Expected Piece, but was %i", result.unit);
}

- (void)testPrimitiveQuantitySumPounds {
	Quantity q1 = MakeQuantityFromPounds(2.4);
	Quantity q2 = MakeQuantityFromPounds(3.1);
	Quantity result = SumQuantity(q1, q2);
	
	STAssertEqualsWithAccuracy(result.quantity, 5.5, 0.0001, @"Expected 5.5, but was %f", result.quantity);
	STAssertEquals(result.unit, QuantityUnitPound, @"Expected Pound, but was %i", result.unit);
}

- (void)testPrimitiveQuantitySumMixed {
	Quantity q1 = MakeQuantityFromPounds(2.7);
	Quantity q2 = MakeQuantityFromPieces(4);
	STAssertThrows(SumQuantity(q1, q2), @"Mixed quantity should throw");
}

- (void)testPrimitiveQuantitySubtractPieces {
	Quantity q1 = MakeQuantityFromPieces(6);
	Quantity q2 = MakeQuantityFromPieces(3);
	Quantity result = SubtractQuantity(q1, q2);
	
	STAssertEqualsWithAccuracy(result.quantity, 3.0, 0.0001, @"Expected 3, but was %f", result.quantity);
	STAssertEquals(result.unit, QuantityUnitPiece, @"Expected Piece, but was %i", result.unit);
}

- (void)testPrimitiveQuantitySubtractPounds {
	Quantity q1 = MakeQuantityFromPounds(5.6);
	Quantity q2 = MakeQuantityFromPounds(3.7);
	Quantity result = SubtractQuantity(q1, q2);
	
	STAssertEqualsWithAccuracy(result.quantity, 1.9, 0.0001, @"Expected 1.9, but was %f", result.quantity);
	STAssertEquals(result.unit, QuantityUnitPound, @"Expected Pound, but was %i", result.unit);
}


- (void)testPrimitiveQuantityFormatPositive {
	Quantity q1 = MakeQuantityFromPieces(1);
	Quantity q2 = MakeQuantityFromPieces(5);
	Quantity q3 = MakeQuantityFromPounds(1.0);
	Quantity q4 = MakeQuantityFromPounds(6.1875); // 6 ponds and 3 ounches
	
	STAssertTrue([FormatQuantity(q1) isEqualToString:@"1 piece"], @"Expected 1 piece, but was %@", FormatQuantity(q1));
	STAssertTrue([FormatQuantity(q2) isEqualToString:@"5 pieces"], @"Expected 5 pieces, but was %@", FormatQuantity(q2));
	STAssertTrue([FormatQuantity(q3) isEqualToString:@"1 pound"], @"Expected 1 pound, but was %@", FormatQuantity(q3));
	STAssertTrue([FormatQuantity(q4) isEqualToString:@"6.1875 pounds"], @"Expected 6.1875 pounds, but was %@", FormatQuantity(q4));
}

- (void)testPrimitiveQuantityFormatNegative {
	Quantity q1 = MakeQuantityFromPieces(-2);
	Quantity q2 = MakeQuantityFromPounds(-4.2);
	
	STAssertTrue([FormatQuantity(q1) isEqualToString:@"-2 pieces"], @"Expected -2 pieces, but was %@", FormatQuantity(q1));
	STAssertTrue([FormatQuantity(q2) isEqualToString:@"-4.2 pounds"], @"Expected -4.2 pounds, but was %@", FormatQuantity(q2));
}

- (void)testPrimitiveMultiplyPositive {
	Money m = MakeMoney(2, 99);
	Quantity q1 = MakeQuantityFromPieces(6);
	Quantity q2 = MakeQuantityFromPounds(0.25);
	
	Money result1 = Multiply(m, q1);
	Money result2 = Multiply(m, q2);
	
	STAssertEquals(TotalCents(result1), 1794, @"Expected $17.94, but was %@", FormatMoney(result1));
	STAssertEquals(TotalCents(result2), 75, @"Expected $0.75, but was %@", FormatMoney(result2));
}

- (void)testPrimitiveMultiplyNegative {
	Money m = MakeMoney(-2, 1);
	Quantity q1 = MakeQuantityFromPieces(4);
	Quantity q2 = MakeQuantityFromPounds(0.75);
	
	Money result1 = Multiply(m, q1);
	Money result2 = Multiply(m, q2);
	
	STAssertEquals(TotalCents(result1), -796, @"Expected ($7.96), but was %@", FormatMoney(result1));
	STAssertEquals(TotalCents(result2), -149, @"Expected ($1.49), but was %@", FormatMoney(result2));
}

- (void)testPrimitiveMultiplyMoneyBy {
	Money m = MakeMoney(3, 47);
	Money result = MultiplyMoneyBy(m, 2.18);
	
	STAssertEquals(TotalCents(result), 757, @"Expected $7.57, but was %@", FormatMoney(result));
}

- (void)testPrimitiveMultiplyQuantityBy {
	Quantity q = MakeQuantityFromPounds(3.5);
	Quantity result = MultiplyQuantityBy(q, 2.2);
	
	STAssertEqualsWithAccuracy(result.quantity, 7.7, 0.0001, @"Expected 7.7 pounds, but was %@", FormatQuantity(result));
}

- (void)testPrimitiveDividePositive {
	Money m1 = MakeMoney(17, 94);
	Money m2 = MakeMoney(0, 75);
	Quantity q1 = MakeQuantityFromPieces(6);
	Quantity q2 = MakeQuantityFromPounds(0.25);
	
	Money result1 = Divide(m1, q1);
	Money result2 = Divide(m2, q2);
	
	STAssertEquals(TotalCents(result1), 299, @"Expected $2.99, but was %@", FormatMoney(result1));
	STAssertEquals(TotalCents(result2), 300, @"Expected $3.00, but was %@", FormatMoney(result2));
}

- (void)testPrimitiveDivideNegative {
	Money m1 = MakeMoney(-7, -96);
	Money m2 = MakeMoney(-1, -49);
	Quantity q1 = MakeQuantityFromPieces(4);
	Quantity q2 = MakeQuantityFromPounds(0.75);
	
	Money result1 = Divide(m1, q1);
	Money result2 = Divide(m2, q2);
	
	STAssertEquals(TotalCents(result1), -199, @"Expected ($1.99), but was %@", FormatMoney(result1));
	STAssertEquals(TotalCents(result2), -198, @"Expected ($1.98), but was %@", FormatMoney(result2));
}

- (void)testPrimitiveDivideMoneyBy {
	Money m = MakeMoney(6, 21);
	Money result = DivideMoneyBy(m, 2.73);
	
	STAssertEquals(TotalCents(result), 228, @"Expected $2.28, but was %@", FormatMoney(result));
}

- (void)testPrimitiveDivideQuantityBy {
	Quantity q = MakeQuantityFromPounds(10.5);
	Quantity result = DivideQuantityBy(q, 4.0);
	
	STAssertEqualsWithAccuracy(result.quantity, 2.625, 0.0001, @"Expected 2.625 pounds, but was %@", FormatQuantity(result));
}

- (void)testPrimitiveDivideMoney {
	Money m1 = MakeMoney(10, 22);
	Money m2 = MakeMoney(2, 42);
	
	double result = DivideMoney(m1, m2);
	STAssertEqualsWithAccuracy(result, 4.2231, 0.0001, @"Expected 4.2231, but was %f", result);
}

- (void)testPrimitiveDivideQuantityPounds {
	Quantity q1 = MakeQuantityFromPounds(21.34);
	Quantity q2 = MakeQuantityFromPounds(3.48);
	
	double result = DivideQuantity(q1, q2);
	STAssertEqualsWithAccuracy(result, 6.1322, 0.0001, @"Expected 6.1322, but was %f", result);
}

- (void)testPrimitiveDivideQuantityMixed {
	Quantity q1 = MakeQuantityFromPounds(21.34);
	Quantity q2 = MakeQuantityFromPieces(3);
	
	STAssertThrows(DivideQuantity(q1, q2), @"Mixed quantity should throw");
}

@end
